package com.wiscamp.ninechapters.panels.domain.services;

import com.wiscamp.ninechapters.panels.domain.repositories.PanelsErrorCodes;
import com.wiscamp.ninechapters.panels.domain.entities.Group;
import com.wiscamp.ninechapters.panels.domain.entities.Role;
import com.wiscamp.ninechapters.panels.domain.entities.User;
import com.wiscamp.ninechapters.panels.domain.repositories.GroupRepository;
import com.wiscamp.ninechapters.panels.domain.repositories.RoleRepository;
import com.wiscamp.ninechapters.panels.domain.repositories.UserRepository;
import cube.common.cache.CacheManagerNames;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.domain.DomainService;
import cube.ddd.exception.ExceptionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

@Service
public class GroupService implements DomainService {
    private final GroupRepository groupRepository;

    private final UserRepository userRepository;

    private final RoleRepository roleRepository;

    private final String cacheName = "groups";

    public GroupService(GroupRepository groupRepository, UserRepository userRepository, RoleRepository roleRepository) {
        this.groupRepository = groupRepository;
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
    }

    @HandleServiceException
    @Cacheable(value = cacheName, key = "#groupId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Group getGroup(long groupId) {
        var group = groupRepository.getGroup(groupId);
        if (Objects.isNull(group)) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.PARAMETER_NOT_FOUND, groupId);
        }
        return group;
    }

    @HandleServiceException
    public Collection<User> getUsersByGroup(long groupId) {
        var group = getGroup(groupId);
        if (Objects.nonNull(group) && !group.getUserIds().isEmpty()) {
            return userRepository.getUsersByIds(group.getUserIds());
        }
        return new ArrayList<>();
    }

    @HandleServiceException
    public Collection<Role> getRolesByGroup(long groupId) {
        var group = getGroup(groupId);
        if (Objects.nonNull(group) && !group.getRoleIds().isEmpty()) {
            return roleRepository.getRolesByIds(group.getRoleIds());
        }
        return new ArrayList<>();
    }

    @HandleServiceException
    @CachePut(value = cacheName, key = "#group.groupId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Group createGroup(Group group, long operatorId) {
        var existedGroup = groupRepository.getGroupByCode(group.getApplicationId(), group.getGroupCode());
        if (Objects.nonNull(existedGroup)) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.PARAMETER_CODE_EXISTED, group);
        }
        group.createBy(operatorId);
        return groupRepository.saveGroup(group);
    }

    @HandleServiceException
    @CachePut(value = cacheName, key = "#group.groupId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Group updateGroup(Group group, long operatorId) {
        var existedGroup = getGroup(group.getGroupId());

        existedGroup = groupRepository.getGroupByCode(group.getApplicationId(), group.getGroupCode());
        if (Objects.nonNull(existedGroup) && existedGroup.getGroupId() != group.getGroupId()) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.GROUP_CODE_EXISTED, group);
        }
        group.updateBy(operatorId);
        return groupRepository.saveGroup(group);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean enableGroup(long groupId, long operatorId) {
        var group = getGroup(groupId);
        if (Objects.isNull(group)) return false;
        // 记录操作日志
        group.enable();
        group.updateBy(operatorId);
        groupRepository.saveGroup(group);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean disableGroup(long groupId, long operatorId) {
        var group = getGroup(groupId);
        if (Objects.isNull(group)) return false;
        // 记录操作日志
        group.disable();
        group.updateBy(operatorId);
        groupRepository.saveGroup(group);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean deleteGroup(long groupId, long operatorId) {
        var group = getGroup(groupId);
        if (Objects.isNull(group)) return false;
        // 记录操作日志
        group.delete();
        group.updateBy(operatorId);
        groupRepository.saveGroup(group);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean bindGroupRole(long groupId, long roleId) {
        return groupRepository.bindGroupRole(groupId, roleId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean unbindGroupRole(long groupId, long roleId) {
        return groupRepository.unbindGroupRole(groupId, roleId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean bindGroupUser(long groupId, long userId) {
        return groupRepository.bindGroupUser(groupId, userId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#groupId")
    public boolean unbindGroupUser(long groupId, long userId) {
        return groupRepository.unbindGroupUser(groupId, userId);
    }
}
